

#include "storage.h"


table_t* dataset = NULL;
table_t* temp_table = NULL;
table_t* expire = NULL;


unsigned int mvalue_type_to_dns_type[] = { BEGIN_TYPE, A,NS,CNAME,MX };
unsigned int dns_type_to_mvalue_type[NXT] = {0,_A,_NS,0,0,_CNAME,0,0,0,0,0,0,0,0,0,_MX,0,0,0,0,0,0,0,0,0,0,0,0,_AAAA,0};
										//	 0  1   2 3 4      5 6 7 8 9 0 1 2 3 4   5 6 7 8 9 0 1 2 3 4 5 6 7     8 9 





static int add_to_expire(void ** record, unsigned char * key, void * val)
{
	unsigned char * buff = (unsigned char *)(*record);
	if (buff)
	{
		free(buff);
	}
	*record = val;
	return 1;
}



inline table_t * get_expire()
{
	if (!expire)
	{
		expire = create_table(1);
		expire->add_value = add_to_expire;

	}
	return expire;
}



void  ttl_expire_callback(void* per)
{
	tnode * p_tnode = (tnode*)per;
	dns_info_t info;
	unsigned char *key = p_tnode->param;
	int key_len = strlen(key) + 1;
	int buff_len = DNS_HEADER_SIZE + sizeof(dns_query_par_t) + key_len;
	expire_record_t * record =(expire_record_t*) malloc(sizeof(expire_record_t)+buff_len);
	record->buff_len = buff_len;
	info.buff = record->buff;
	info.buff_len = buff_len;
	info.start = 0;
	info.start = dns_unmarshal_header(record->buff, 0, buff_len, &info.header);
	memset(info.header, 0, DNS_HEADER_SIZE);
	dns_fill_query(&info, key, A, IN);
	dns_fill_header(&info);
/*	printf("insert expire %s %x\n", key, record);*/
	insert_to_table(get_expire(), key, key_len, record, 0);
}


unsigned int take_from_expire(unsigned char * out,unsigned int out_len)
{
	expire_record_t* record = (expire_record_t*)pop_from_table(get_expire(), 0);
	unsigned int len = 0;
	if (!record|| record->buff_len > out_len || !out )
		return len;
/*	printf("take from expire\n");*/
	memcpy(out, record->buff, record->buff_len);
	len = record->buff_len;
	free(record);
	return len;
}










static int add_to_record(void ** record, unsigned char * key,void * val)
{

	record_t* _record = (record_t*)(*record);
	mvalue_t* _val = (mvalue_t*)val;

	if (!_record)
	{
		_record = (record_t*)malloc(sizeof(record_t));
		memset(_record, 0, sizeof(record_t));
	}
	*record = _record;
	if (!val)
	{
		return 0;
	}

	if (_record->records[_val->type])
		free(_record->record_a);

	_record->records[_val->type] = _val;

	timer_add(_val->ttl, 0, ttl_expire_callback, key, 0);

	return 1;
}



mvalue_t* create_mvalue(unsigned int len)
{
	unsigned char * buff = malloc(sizeof(mvalue_t) + len);
	mvalue_t* mv = (mvalue_t*)buff;
	mv->hits = 0;
	mv->len = len;
	mv->num = 0;
	mv->ttl = 0;
	mv->type = 0;
	return mv;
}

void append_to_mvalue(mvalue_t*val, unsigned char* buff, unsigned int len)
{

}

mvalue_t* record_to_mvalues(dns_info_t* info, int *mvalue_len)
{
// 	mvalue_t* val;
//
// 	int len = 0, pos = 0, i = 0;
// 	unsigned char*key = NULL;
//
// 	for (; i < info->header->ans_count; i++)
// 	{
// 		if (key == NULL)
// 		{
// 			key = info->records[i].name;
// 		}
// 		else if (strcmp(key, q->records[i].name) != 0)
// 		{
// 			val = create_mvalue(len);
// 			unsigned char* buff = val->buff;
// 			val->type = _A;
// 			int j = pos;
// 			for (; j < i; j++)
// 			{
// 				memcpy(buff, info->records[j].rdata, info->records[j].par->rdata_len);
// 				buff += info->records[j].par->rdata_len;
// 				val->num++;
// 			}
// 			pos = i;
// 			key = info->records[i].name;
// 		}
// 		len += info->records[i].par->rdata_len;
// 	}
// 	val = create_mvalue(len);
// 	unsigned char* buff = mv->buff;
// 	int j = pos;
// 	for (; j < i; j++)
// 	{
// 		*((int*)buff) = *((int*)q->records[j].rdata);
// 		buff += sizeof(int);
// 		val->num++;
// 	}
	return NULL;
}









int iptoint(const char *ip)
{
	return inet_addr(ip);
}

inline table_t* get_temp_table()
{
	if (!temp_table)
	{
		temp_table = create_table(128);
		temp_table->add_value = add_to_record;
	}
	return temp_table;
}

inline table_t* get_dataset() {
	if (!dataset)
	{
		dataset = create_table(1024);
		dataset->add_value = add_to_record;
		mvalue_t*val = create_mvalue(sizeof(int));
		unsigned char* buff = val->buff;
		val->type = _A;
		int res = iptoint("192.35.51.30");
		memcpy(buff, &res, sizeof(int));
		val->num = 1;
		insert_to_table(dataset, "3win", 5, val, 0);


		val = create_mvalue(5);
		buff = val->buff;
		val->type = _NS;
		val->num = 1;
		memcpy(buff, "3win", 5);
		insert_to_table(dataset, "\003com", 5, val, 0);
		//com.			172800	IN	NS	a.gtld - servers.net.
		//a.gtld - servers.net.	172800	IN	A	192.5.6.30


		{
			mvalue_t* val = create_mvalue(sizeof(int));
			val->type = _A;
			unsigned char *buff = val->buff;
			int res = iptoint("199.254.31.1");
			memcpy(buff, &res, sizeof(int));
			val->num = 1;
			insert_to_table(dataset, "4win", 5, val, 0);

			val = create_mvalue(5);
			buff = val->buff;
			val->type = _NS;
			val->num = 1;
			memcpy(buff, "4win", 5);
			insert_to_table(dataset, "\004info", 6, val, 0);

			//info.			172800	IN	NS	a0.info.afilias-nst.info.
			//a0.info.afilias-nst.info.	172800	IN	A	199.254.31.1
		}
	}
	return dataset;
}

void insert_ns_to_dataset(dns_info_t *info) {


	if (!info || (info->header->auth_count== 0 && info->header->add_count ==0 ))
	{
		return;
	}
	int i = info->header->ans_count;
	unsigned int ttl = -1;  //����ֵ
	unsigned char * key = NULL;
	mvalue_t* val = NULL;
	int all_rdata_len = 0;
	int start = info->header->ans_count, end = 0;
	for (; i< info->header->ans_count +info->header->add_count+info->header->auth_count; i++)
	{
		dns_record_t record = info->records[i];
		if (key== NULL)
		{
			key = record.name;
		}
		else if (strcmp(key,record.name)!=0)
		{
			end = i;
			int j = 0;
			val = create_mvalue(all_rdata_len);
			unsigned char *buff = val->buff;
			val->type = _NS;

			for (j =start ;j< end ;j++)
			{
				memcpy(buff, info->records[j].rdata, info->records[j].par->rdata_len);
				buff += info->records[j].par->rdata_len;
				val->num++;
			}
			insert_value_to_dataset(key, val);   //���� ������ ��Ӧ ns ����
			key = record.name;
			start = i;
			all_rdata_len = 0;
			ttl = -1;
		}
		insert_value_to_dataset(record.rdata, NULL);  //�Ȳ���ns �����Ŀ� key
		all_rdata_len += record.par->rdata_len;
		ttl = (ttl <= record.par->ttl) ? ttl : record.par->ttl;

	}
	//����һ��key
	end = i;
	int j = 0, rdata_len = 0;
	val = create_mvalue(all_rdata_len);
	unsigned char *buff = val->buff;
	val->type = _NS;
	for (j = start; j < end; j++)
	{
		memcpy(buff, info->records[j].rdata, info->records[j].par->rdata_len);
		buff += info->records[j].par->rdata_len;
		val->num++;
	}
	insert_value_to_dataset(key, val);//���� ������ ��Ӧ ns ����
}




void insert_a_to_dataset(dns_info_t*info, unsigned int start, unsigned int end) {
	if (start == end)
	{
		return;
	}
	int ip_num = 0, pos = start, i = start;
	unsigned int ttl = -1;  //����ֵ
	record_t* record = NULL;
	unsigned char*key = NULL;
	unsigned int mvalue_type = _A;
	int all_rdata_len = 0;
	for (;i<end; i++)
	{
		if (key ==  NULL)
		{
			key = info->records[i].name;
			mvalue_type = dns_type_to_mvalue_type[info->records[i].par->type];
		}
		else if (strcmp(key, info->records[i].name) != 0 || mvalue_type != dns_type_to_mvalue_type[info->records[i].par->type])
		{
			if (mvalue_type == _CNAME)
			{
				int i = 0;
			}
			mvalue_t* val = create_mvalue(all_rdata_len);
			val->type = mvalue_type;
			unsigned char* buff = val->buff;
			int j = pos;
			for (; j <i ;j++)
			{
				memcpy(buff, info->records[j].rdata, info->records[j].par->rdata_len);
				buff += info->records[j].par->rdata_len;
				val->num++;
			}
			record = find_record_from_dataset(key);
			if (record)
			{
				add_to_record((void**)&record, key, val);
			}
			else
			{
				insert_to_table(get_temp_table(), key, strlen(key) + 1, val, 0);
			}
			pos = i;
			key = info->records[i].name;
			mvalue_type = dns_type_to_mvalue_type[info->records[i].par->type];
			ttl = -1;
			all_rdata_len = 0;
		}
		all_rdata_len += info->records[i].par->rdata_len;
		/*ttl = (ttl <= info->records[i].par->ttl) ? ttl : info->records[i].par->ttl;*/
	}
	if (mvalue_type == _CNAME)
	{
		int i = 0;
	}
	mvalue_t* val = create_mvalue(all_rdata_len);
	unsigned char* buff = val->buff;
	val->type = mvalue_type;
	int j = pos;
	for (; j < i; j++)
	{
		memcpy(buff, info->records[j].rdata, info->records[j].par->rdata_len);
		buff += info->records[j].par->rdata_len;
		val->num++;
	}
	record = find_record_from_dataset(key);
	if (record)
	{
		add_to_record((void**)&record, key, val);
	}
	else
	{
		insert_to_table(get_temp_table(), key, strlen(key) + 1, val, 0);
	}
}




unsigned int get_dns_type(unsigned int mvalue_type)
{
	return mvalue_type_to_dns_type[mvalue_type];
}

unsigned int get_mvalue_type(unsigned int dns_type)
{
	return dns_type_to_mvalue_type[dns_type];
}




record_t* find_record_from_temp(unsigned char * key) {
	table_t* table = get_temp_table();
	record_t* record = (record_t*)find_from_table(table, key, strlen(key) + 1, 0);
	return record;
}




record_t* find_record_from_dataset(unsigned char * key) {
	table_t* dataset = get_dataset();
	record_t* record = (record_t*)find_from_table(dataset, key, strlen(key)+1, 0);
	return record;
}

mvalue_t * find_value_from_dataset(unsigned char * key, uint32_t type)
{
	table_t* dataset = get_dataset();
	record_t* record = (record_t*)find_from_table(dataset, key,strlen(key)+1, 0);
	if (!record)
	{
		return NULL;
	}
	mvalue_t* val = record->records[dns_type_to_mvalue_type[type]];
	return val;
}

int insert_value_to_dataset(unsigned char * key, mvalue_t* val) {
	table_t* dataset = get_dataset();
	insert_to_table(dataset, key, strlen(key)+1, val, 0);
}

void init_request_info(dns_info_t *src, request_info *rinfo)
{
	rinfo->origin_domain[0] = '\0';
	rinfo->node = NULL;
	rinfo->type = 0;
	rinfo->max_try = 0;
	rinfo->stime = 0;
	//memset(rinfo, 0, sizeof(request_info));
	pthread_mutex_init(&rinfo->_lock, NULL);
	//check_dns_name(src->buff + dns_header_size, &rinfo->lowerdomain);
}

void init_request_node(request_node *ninfo)
{
	memset(ninfo, 0, sizeof(request_node));
}

void init_request_info_dnspod(request_info *rinfo)
{
	memset(rinfo, 0, sizeof(request_info));
	pthread_mutex_init(&rinfo->_lock, NULL);
}

unsigned int get_mvalue_rdata_len(unsigned char * buff, unsigned int type)
{
	unsigned int len = 0;
	switch (type)
	{
	case A:
		len = 4;
		break;
	case CNAME:
		len = strlen(buff) + 1;
		break;
	case AAAA:
		len = 16;
		break;
	case MX:
		len = 2 + strlen(buff + 2) + 1;  //mx rdata格式
		break;
	case NS:
		len = strlen(buff) + 1;
		break;
	default:
		break;
	}



	return len;
}
